package cn.dubito.miaosha.controller;

import cn.dubito.miaosha.controller.access.AccessLimit;
import cn.dubito.miaosha.controller.vo.CodeMsg;
import cn.dubito.miaosha.controller.vo.Result;
import cn.dubito.miaosha.domain.SeckillOrder;
import cn.dubito.miaosha.domain.SeckillUser;
import cn.dubito.miaosha.rabbitmq.message.SeckillMessage;
import cn.dubito.miaosha.rabbitmq.send.MqSender;
import cn.dubito.miaosha.redis.GoodsKey;
import cn.dubito.miaosha.redis.RedisService;
import cn.dubito.miaosha.service.GoodsService;
import cn.dubito.miaosha.service.OrderService;
import cn.dubito.miaosha.service.SeckillService;
import cn.dubito.miaosha.vo.GoodsVO;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author liliang
 * @description:
 * @date 2018/3/31.
 */
@Controller
public class SeckillController implements InitializingBean {

    @Autowired
    private GoodsService goodsService;

    @Autowired
    private OrderService orderService;

    @Autowired
    private SeckillService seckillService;

    @Autowired
    private RedisService redisService;

    @Autowired
    private MqSender mqSender;

    private Map<Long, Boolean> localOverMap = new HashMap<Long, Boolean>();


    /**
     * 系统初始化,设置商品数量到缓存中
     *
     * @throws Exception
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        List<GoodsVO> goodsList = goodsService.listGoodsVo();
        if (goodsList != null && goodsList.size() > 0) {
            for (GoodsVO goodsVO : goodsList) {
                redisService.set(GoodsKey.getBySeckillGoodsStock, String.valueOf(goodsVO.getId()), goodsVO.getStockCount());
                localOverMap.put(goodsVO.getId(), false);
            }
        }
    }


    @RequestMapping(value = "/verifyCode", method = RequestMethod.GET)
    @ResponseBody
    public Result<String> getVerifyCode(HttpServletResponse response, SeckillUser user, @RequestParam("goodsId") long goodsId) {
        if (user == null) {
            return Result.error(CodeMsg.SESSION_ERROR);
        }
        BufferedImage image = seckillService.createVerifyCodeImage(user, goodsId);
        try {
            ServletOutputStream out = response.getOutputStream();
            ImageIO.write(image, "JPEG", out);
            out.flush();
            out.close();
            return null;
        } catch (Exception e) {
            return Result.error(CodeMsg.MIAOSHA_FAIL);
        }
    }


    /**
     * 验证秒杀路径
     *
     * @param user
     * @param goodsId
     * @return
     */
    @AccessLimit(seconds=5,hitCount=5)
    @RequestMapping(value = "/seckillPath", method = RequestMethod.GET)
    @ResponseBody
    public Result<String> seckillPath(SeckillUser user, @RequestParam("goodsId") long goodsId,
                                      @RequestParam(value = "verifyCode") Integer verifyCode) {
        if (user == null) {
            return Result.error(CodeMsg.SESSION_ERROR);
        }
        if (verifyCode == null) {
            return Result.error(CodeMsg.CODE_IS_NULL);
        }

        boolean checkCode = seckillService.checkCode(user, goodsId, verifyCode);
        if (!checkCode) {
            return Result.error(CodeMsg.CODE_FAIL);
        }
        String path = seckillService.createSeckillPath(user, goodsId);
        return Result.success(path);
    }

    /**
     * orderId 成功
     * -1 失败
     * 0 排队中
     *
     * @param user
     * @param goodsId
     * @return
     */
    @RequestMapping(value = "/result", method = RequestMethod.GET)
    @ResponseBody
    public Result<Long> seckillResult(SeckillUser user, @RequestParam("goodsId") long goodsId) {
        if (user == null) {
            return Result.error(CodeMsg.SESSION_ERROR);
        }
        long result = seckillService.getSeckillResult(user.getId(), goodsId);
        return Result.success(result);
    }

    @RequestMapping(value = "{path}/seckill", method = RequestMethod.POST)
    @ResponseBody
    public Result<Integer> seckill(SeckillUser user,
                                   @RequestParam("goodsId") long goodsId,
                                   @PathVariable("path") String path) {
        if (user == null) {
            return Result.error(CodeMsg.SESSION_ERROR);
        }

        Boolean isOver = localOverMap.get(goodsId);
        if (isOver) {
            return Result.error(CodeMsg.MIAO_SHA_OVER);
        }

        // 验证 path
        boolean checkPath = seckillService.checkPath(path, user, goodsId);
        if (!checkPath) {
            return Result.error(CodeMsg.REQUEST_ILLEGAL);
        }

        //  减少缓存中的库存
        Long stock = redisService.decr(GoodsKey.getBySeckillGoodsStock, String.valueOf(goodsId));
        if (stock <= 0) {
            localOverMap.put(goodsId, true);
            return Result.error(CodeMsg.MIAO_SHA_OVER);
        }

        // 是否重复秒杀
        SeckillOrder seckillOrder = orderService.getSeckillOrderByUserIdAndGoodsId(user.getId(), goodsId);
        if (seckillOrder != null) {
            return Result.error(CodeMsg.REPEATE_MIAOSHA);
        }

        // 入队列
        SeckillMessage message = new SeckillMessage();
        message.setUser(user);
        message.setGoodsId(goodsId);
        mqSender.sendSeckillMessage(message);

        return Result.success(0);

//        // 判断库存
//        GoodsVO goods = goodsService.getGoodsDetailByGoodsId(goodsId);
//        int stockCount = goods.getStockCount();
//        if (stockCount <= 0) {
//            return Result.error(CodeMsg.MIAO_SHA_OVER);
//        }
//        // 是否重复秒杀
//        SeckillOrder seckillOrder = orderService.getSeckillOrderByUserIdAndGoodsId(user.getId(), goodsId);
//        if (seckillOrder != null) {
//            return Result.error(CodeMsg.REPEATE_MIAOSHA);
//        }
//        // 减库存,下订单,写入秒杀订单
//        return Result.success(seckillService.seckill(user, goods));
    }

}
